﻿using System.Diagnostics;
/// <summary>
/// https://leetcode-cn.com/problems/minimum-path-sum/
/// </summary>
public class Solution
{
    private T GetOrDefault<T>(T[,] values, int index1, int index2, T defaultVaue)
    {
        if (index1 >= 0 && index1 < values.GetLength(0)
            && index2 >= 0 && index2 < values.GetLength(1))
        {
            return values[index1, index2];
        }
        else
            return defaultVaue;
    }
    private T GetOrDefault<T>(T[][] values, int index1, int index2, T defaultVaue)
    {
        if (index1 >= 0 && index1 < values.Length
            && index2 >= 0 && index2 < values[0].Length)
        {
            return values[index1][index2];
        }
        else
            return defaultVaue;
    }
    private int? Min(params int?[] values)
    {
        int? result = null;
        foreach (var value in values)
        {
            if (value.HasValue)
            {
                if (!result.HasValue)
                    result = value;
                else
                    result = Math.Min(result.Value, value.Value);
            }
        }
        return result;
    }

    public int MinPathSum(int[][] grid)
    {
        int?[,] resultMap = new int?[grid.Length, grid[0].Length];
        bool continuing = true;
        for (int i = 0; continuing; i++)
        {
            continuing = i < resultMap.GetLength(0);
            if (continuing)
            {
                for (int j = 0; j < resultMap.GetLength(1); j++)
                {
                    if (i is 0 && j is 0)
                        resultMap[i, j] = 0;
                    else
                        resultMap[i, j] =
                            this.Min(
                                this.GetOrDefault(resultMap, i - 1, j, null) + this.GetOrDefault(grid, i - 1, j, 0),
                                this.GetOrDefault(resultMap, i, j - 1, null) + this.GetOrDefault(grid, i, j - 1, 0));
                }
            }

            if (i < resultMap.GetLength(1))
            {
                continuing = true;
                for (int j = 0; j < resultMap.GetLength(0); j++)
                {
                    if (i is 0 && j is 0)
                        resultMap[j, i] = 0;
                    else
                        resultMap[j, i] =
                            this.Min(
                                this.GetOrDefault(resultMap, j - 1, i, null) + this.GetOrDefault(grid, j - 1, i, 0),
                                this.GetOrDefault(resultMap, j, i - 1, null) + this.GetOrDefault(grid, j, i - 1, 0));
                }
            }
        }
        var result = resultMap[resultMap.GetLength(0) - 1, resultMap.GetLength(1) - 1];
        Debug.Assert(result.HasValue);
        return result.Value + grid[resultMap.GetLength(0) - 1][resultMap.GetLength(1) - 1];
    }
}